#!/bin/bash

#  helper script: download coreboot
#
#	Copyright (C) 2014, 2015, 2016, 2020, 2021 Leah Rowe <info@minifree.org>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

[ "x${DEBUG+set}" = 'xset' ] && set -v
set -u -e

# Error handling is extreme in this script.
# This script handles the internet, and Git. Both are inherently unreliable.

[[ -f osbmk_error ]] && rm -f osbmk_error

rm -f resources/coreboot/*/seen

downloadfor() {

	board="${1}"
    cbtree="undefined"
	cbrevision="undefined"

    # The loop will always exit, but this while loop is crafted
    # such that a tree referencing a tree that references another tree is possible
    # (and so on)
    while true; do
        cbrevision="undefined"
        cbtree="undefined"

    	if [ ! -f "resources/coreboot/${board}/board.cfg" ]; then
	    	printf "ERROR: download/coreboot: board.cfg does not exist for '%s'\n" "${board}"
            return 1
	    fi

        if [ -f "resources/coreboot/${board}/seen" ]; then
            printf "ERROR: download/coreboot: logical loop; '%s' board.cfg refers to another tree, which ultimately refers back to '%s'.\n" "${board}" "${board}"
            return 1
        fi

        # This is to override $cbrevision and $cbtree
	    source "resources/coreboot/${board}/board.cfg" || touch ../osbmk_error
        if [ -f osbmk_error ]; then
            printf "ERROR: download/coreboot: problem sourcing %s/board.cfg\n" "${board}"
            return 1
        fi
        touch "resources/coreboot/${board}/seen"

        if [ "${board}" != "${cbtree}" ]; then
            board="${cbtree}"
        else
            if [ "${cbtree}" = "undefined" ]; then
                printf "ERROR: download/coreboot: tree name undefined for '%s\n'" "${board}"
                return 1
            fi

            if [ "${cbrevision}" = "undefined" ]; then
                printf "ERROR: download/coreboot: commit ID undefined for '%s'\n" "${board}"
                return 1
            fi
            break
        fi
    done

    rm -f resources/coreboot/*/seen

    if [ -d "coreboot/${cbtree}" ]; then
        printf "REMARK: download/coreboot: directory for '%s' already exists. Skipping setup.\n" "${cbtree}"
        if [ "${cbtree}" != "${1}" ]; then
            printf "(for board: '${1}')\n"
        fi
        return 0
    fi

    if [ ! -d coreboot ]; then
        mkdir "coreboot/"
    fi
    if [ ! -d coreboot ]; then
        printf "ERROR: download/coreboot: directory not created. Check file system permissions\n"
        return 1
    fi

    cd "coreboot/"

    if [ ! -d coreboot/.git ] && [ -d coreboot ]; then
        rm -Rf coreboot/
    fi

    if [ ! -d coreboot ]; then
        printf "Download coreboot from upstream:\n"
        git clone https://review.coreboot.org/coreboot || rm -Rf coreboot
        if [ ! -d coreboot ]; then
            printf "WARNING: Upstream failed. Trying backup github repository:\n"
            git clone https://github.com/coreboot/coreboot.git || rm -Rf coreboot
        fi
        if [ ! -d coreboot ]; then 
            printf "ERROR: download/coreboot: Problem with git-clone. Network issue?\n"
            cd ../; return 1
        fi
    else
        ( cd coreboot/; git pull || touch ../osbmk_error )
        if [ -f ../osbmk_error ]; then
            printf "ERROR: download/coreboot: Problem with git-pull. Network issue?\n"
            cd ../; return 1
        fi
    fi

    cp -R coreboot "${cbtree}" || touch ../osbmk_error
    if [ -d ../osbmk_error ]; then
        printf "ERROR: download/coreboot: Unable to copy directory. Check file system permissions or free space.\n"
        rm -Rf "${cbtree}/"
        cd ../; return 1
    fi

    cd ${cbtree}/

    git reset --hard ${cbrevision} || touch ../../osbmk_error
    if [ -f ../../osbmk_error ]; then
        printf "ERROR: download/coreboot: Unable to reset to commit ID/tag '%s' for board '%s' on tree '%s'\n" "${cbrevision}" "${1}" "${cbtree}"
        cd ../../; return 1
    fi

    git submodule update --init --checkout || touch ../../osbmk_error
    if [ -f ../../osbmk_error ]; then
        printf "ERROR: download/coreboot: Unable to update submodules for tree '%s'\n" "${cbtree}"
        cd ../../; return 1
    fi

    for patch in ../../resources/coreboot/${cbtree}/patches/*.patch; do
        if [ ! -f "${patch}" ]; then
            continue
        fi

        git am "${patch}" || touch ../../osbmk_error
        if [ -f ../../osbmk_error ]; then
            printf "ERROR: download/coreboot: Unable to apply patch '%s' for board '%s' on tree '%s'" "${patch}" "${1}" "${cbtree}"
            git am --abort
            cd ../../; return 1
        fi
    done

    # extra.sh could be used to patch submodules, if you wanted to
    # It's impossible to predict what submodules will be available, and
    # it's rare that you'd want to patch them, so this is handled by
    # extra.sh on a per-board basis
    # In fact, extra.sh can be used for anything you want.
    if [ -f "../../resources/coreboot/${board}/extra.sh" ]; then
        "../../resources/coreboot/${board}/extra.sh" || touch ../../osbmk_error
        if [ -f ../../osbmk_error ]; then
            cd ../../; return 1
        fi
        return 0
    else
        cd ../../
        return 0
    fi
}

printf "Downloading coreboot and (if exist in build system) applying patches\n"

if [ $# -gt 0 ]; then
    for board in "${@}"; do
        rm -f resources/coreboot/*/seen
        downloadfor "${board}"
        if [ -f osbmk_error ]; then break; fi
    done
else
    for board in resources/coreboot/*; do
        rm -f resources/coreboot/*/seen
	    if [ ! -d "${board}/" ]; then
		    continue
	    fi
        downloadfor "${board##*/}"
        if [ -f osbmk_error ]; then break; fi
    done
fi

rm -f resources/coreboot/*/seen

rm -f "osbmk_error"
printf "\n\n"
exit 0
